/**
 * Copyright (c) 2005-2011 springside.org.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * 
 * $Id: ReflectionUtils.java 1504 2011-03-08 14:49:20Z calvinxiu $
 */
package com.sg.common.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.NestedNullException;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 反射工具类.
 * 
 * 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
 * 
 * @author calvin
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public abstract class ReUtils {
	

	/**
	 * 取得BEAN的字段合集对应的value合集
	 * 
	 * @param descrs  字段field合集
	 * @param bo BEAN
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static String mutiPropertyValue(List<String> descrs,Object bo)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		StringBuilder descrStr = new StringBuilder();
		for (String field : descrs) {// 显示多个描述
			String beanValue = getStr(bo,field);
			descrStr.append(beanValue).append(" ，");
		}
		descrStr.delete(descrStr.length() - 1, descrStr.length());
		return descrStr.toString();
	}
	
	public static void copyValue(Object old, Object newb,
			String field)
			throws NoSuchFieldException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		ReUtils.set(newb, field, ReUtils.get(old, field));
	}


	public static Field findField(Object bean, String key) {
		Class superClass = bean.getClass();
		int ind = StringUtils.indexOf(key, ".");
		if (ind > 0) {
			key = StringUtils.substring(key, 0, ind);
		}
		for (; superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredField(key);
			} catch (SecurityException e) {
			} catch (NoSuchFieldException e) {
			}

		}
		return null;
	}

	public static final String CGLIB_CLASS_SEPARATOR = "$$";

	private static Logger logger = LoggerFactory
			.getLogger(ReUtils.class);

	/**
	 * 调用Getter方法.
	 */
	// public static Object invokeGetterMethod(Object obj, String propertyName)
	// {
	// String getterMethodName = "get" + StringUtils.capitalize(propertyName);
	// return invokeMethod(obj, getterMethodName, new Class[] {}, new Object[]
	// {});
	// }

	/**
	 * 调用Setter方法.使用value的Class来查找Setter方法.
	 */
	// public static void invokeSetterMethod(Object obj, String propertyName,
	// Object value) {
	// invokeSetterMethod(obj, propertyName, value, null);
	// }

	/**
	 * 调用Setter方法.
	 * 
	 * @param propertyType
	 *            用于查找Setter方法,为空时使用value的Class替代.
	 */
	// public static void invokeSetterMethod(Object obj, String propertyName,
	// Object value, Class<?> propertyType) {
	// Class<?> type = propertyType != null ? propertyType : value.getClass();
	// String setterMethodName = "set" + StringUtils.capitalize(propertyName);
	// invokeMethod(obj, setterMethodName, new Class[] { type }, new Object[] {
	// value });
	// }

	/**
	 * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
	 */
	public static Object getFieldValue(final Object obj, final String fieldName) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field ["
					+ fieldName + "] on target [" + obj + "]");
		}

		Object result = null;
		try {
			result = field.get(obj);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常{}", e.getMessage());
		}
		return result;
	}

	/**
	 * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
	 */
	public static void setFieldValue(final Object obj, final String fieldName,
			final Object value) {
		Field field = getAccessibleField(obj, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field ["
					+ fieldName + "] on target [" + obj + "]");
		}

		try {
			field.set(obj, value);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常:{}", e.getMessage());
		}
	}

	/**
	 * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
	 * 
	 * 如向上转型到Object仍无法找到, 返回null.
	 */
	public static Field getAccessibleField(final Object obj,
			final String fieldName) {
		AssertUtils.notNull(obj, "object不能为空");
		AssertUtils.hasText(fieldName, "fieldName");
		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				Field field = superClass.getDeclaredField(fieldName);
				field.setAccessible(true);
				return field;
			} catch (NoSuchFieldException e) {// NOSONAR
				// Field不在当前类定义,继续向上转型
			}
		}
		return null;
	}
	
	public static void set(Object bean, String name,Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
		try {
		PropertyUtils.setProperty(bean, name, value);
		} catch (NestedNullException e) {
		}
	}

	public static Object get(Object bean, String field)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		try {
			Object property = PropertyUtils.getProperty(bean, field);
			return property;
		} catch (NestedNullException e) {
			return "";
		}
	}

	public static String getStr(Object bean, String field) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
		try {
			Object property = PropertyUtils.getProperty(bean, field);
			if(property!=null)
				return String.valueOf(property);
			
		} catch (NestedNullException e) {
		}
		return "";
	}

	/**
	 * 对于被cglib AOP过的对象, 取得真实的Class类型.
	 */
	public static Class<?> getUserClass(Class<?> clazz) {
		if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) {
			Class<?> superClass = clazz.getSuperclass();
			if (superClass != null && !Object.class.equals(superClass)) {
				return superClass;
			}
		}
		return clazz;
	}

	/**
	 * 直接调用对象方法, 无视private/protected修饰符. 用于一次性调用的情况.
	 */
	public static Object invokeMethod(final Object obj,
			final String methodName, final Class<?>[] parameterTypes,
			final Object[] args) {
		Method method = getAccessibleMethod(obj, methodName, parameterTypes);
		if (method == null) {
			throw new IllegalArgumentException("Could not find method ["
					+ methodName + "] on target [" + obj + "]");
		}

		try {
			return method.invoke(obj, args);
		} catch (Exception e) {
			throw convertReflectionExceptionToUnchecked(e);
		}
	}

	/**
	 * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问. 如向上转型到Object仍无法找到, 返回null.
	 * 
	 * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object...
	 * args)
	 */
	public static Method getAccessibleMethod(final Object obj,
			final String methodName, final Class<?>... parameterTypes) {
		AssertUtils.notNull(obj, "object不能为空");

		for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				Method method = superClass.getDeclaredMethod(methodName,
						parameterTypes);

				method.setAccessible(true);

				return method;

			} catch (NoSuchMethodException e) {// NOSONAR
				// Method不在当前类定义,继续向上转型
			}
		}
		return null;
	}

	/**
	 * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 如无法找到, 返回Object.class. eg. public UserDao
	 * extends HibernateDao<User>
	 * 
	 * @param clazz
	 *            The class to introspect
	 * @return the first generic declaration, or Object.class if cannot be
	 *         determined
	 */
	public static <T> Class<T> getSuperClassGenricType(final Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	/**
	 * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 如无法找到, 返回Object.class.
	 * 
	 * 如public UserDao extends HibernateDao<User,Long>
	 * 
	 * @param clazz
	 *            clazz The class to introspect
	 * @param index
	 *            the Index of the generic ddeclaration,start from 0.
	 * @return the index generic declaration, or Object.class if cannot be
	 *         determined
	 */
	public static Class getSuperClassGenricType(final Class clazz,
			final int index) {

		Type genType = clazz.getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			logger.warn(clazz.getSimpleName()
					+ "'s superclass not ParameterizedType");
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			logger.warn("Index: " + index + ", Size of "
					+ clazz.getSimpleName() + "'s Parameterized Type: "
					+ params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			logger.warn(clazz.getSimpleName()
					+ " not set the actual class on superclass generic parameter");
			return Object.class;
		}

		// for (Type type : params) {
		// Class clz = (Class)type;
		// System.out.println(clz.getName());
		// }
		return (Class) params[index];
	}

	/**
	 * 将反射时的checked exception转换为unchecked exception.
	 */
	public static RuntimeException convertReflectionExceptionToUnchecked(
			Exception e) {
		if (e instanceof IllegalAccessException
				|| e instanceof IllegalArgumentException
				|| e instanceof NoSuchMethodException) {
			return new IllegalArgumentException("Reflection Exception.", e);
		} else if (e instanceof InvocationTargetException) {
			return new RuntimeException("Reflection Exception.",
					((InvocationTargetException) e).getTargetException());
		} else if (e instanceof RuntimeException) {
			return (RuntimeException) e;
		}
		return new RuntimeException("Unexpected Checked Exception.", e);
	}

	/**
	 * 按Filed的类型取得Field列表
	 */
	public static List<Field> getFieldsByType(Object object, Class type) {
		ArrayList<Field> list = new ArrayList<Field>();
		Field[] fields = object.getClass().getDeclaredFields();
		for (Field field : fields) {
			if (field.getType().isAssignableFrom(type)) {
				list.add(field);
			}
		}
		return list;
	}

	public static String objToStr(Object object, Class type)
			throws IllegalArgumentException, IllegalAccessException {
		StringBuilder sb = new StringBuilder();
		Field[] fields = type.getDeclaredFields();
		for (Field field : fields) {
			Object str = field.get(object);
			sb.append(field.getName() + "=" + str + ",");
		}
		return sb.toString();
	}

	public static boolean contain(Object bean, String key) {
		Class superClass = bean.getClass();
		int ind = StringUtils.indexOf(key, ".");
		if (ind > 0) {
			key = StringUtils.substring(key, 0, ind);
		}
		for (; superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				superClass.getDeclaredField(key);
				return true;
			} catch (SecurityException e) {
			} catch (NoSuchFieldException e) {
			}

		}
		return false;
	}

	public static Class<?> type(Object bean, String field)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, InstantiationException {
		String[] ss = StringUtils.split(field, ".");
		Class<?> propertyType = bean.getClass();
		for (String s : ss) {
			propertyType = PropertyUtils.getPropertyType(
					propertyType.newInstance(), s);

		}
		return propertyType;
	}



	public static Class<?> typeOneLev(Object bean, String field)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException, InstantiationException {
		String[] ss = StringUtils.split(field, ".");
		Class<?> propertyType = bean.getClass();
		propertyType = PropertyUtils.getPropertyType(
				propertyType.newInstance(), ss[0]);

		return propertyType;
	}
}
